/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.echarts.lib;

import cn.easyplatform.web.ext.echarts.lib.axis.AngleAxis;
import cn.easyplatform.web.ext.echarts.lib.axis.Axis;
import cn.easyplatform.web.ext.echarts.lib.axis.BaseAxis;
import cn.easyplatform.web.ext.echarts.lib.axis.RadiusAxis;
import cn.easyplatform.web.ext.echarts.lib.graphic.*;
import cn.easyplatform.web.ext.echarts.lib.style.TextStyle;
import cn.easyplatform.web.ext.echarts.lib.support.Animation;
import cn.easyplatform.web.ext.echarts.lib.threeD.Axis3D;
import cn.easyplatform.web.ext.echarts.lib.threeD.Grid3D;
import cn.easyplatform.web.ext.echarts.lib.vm.VisualMap;
import cn.easyplatform.web.ext.echarts.lib.zoom.DataZoom;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class Option extends Animation implements Serializable {
    /**
     * 全图默认背景，（详见backgroundColor），默认为无，透明
     */
    private Object backgroundColor;
    /**
     * 数值系列的颜色列表，（详见color），可配数组，eg：['#87cefa', 'rgba(123,123,123,0.5)','...']，当系列数量个数比颜色列表长度大时将循环选取
     */
    private Object[] color;
    /**
     * 全局的字体样式
     */
    private TextStyle textStyle;
    /**
     * 图形的混合模式
     */
    private String blendMode;
    /**
     * 图形数量阈值，决定是否开启单独的 hover 层，在整个图表的图形数量大于该阈值时开启单独的 hover 层
     */
    private Integer hoverLayerThreshold;
    /**
     * 标题组件，包含主标题和副标题
     */
    private Title title;
    /**
     * 图例组件
     */
    private Legend legend;
    /**
     * 直角坐标系内绘图网格，单个 grid 内最多可以放置上下两个 X 轴，左右两个 Y 轴
     */
    private Object grid;
    /**
     * 直角坐标系 grid 中的 x 轴，一般情况下单个 grid 组件最多只能放左右两个 x 轴，多于两个 x 轴需要通过配置 offset 属性防止同个位置多个 x 轴的重叠
     */
    private Object xAxis;
    /**
     * 直角坐标系 grid 中的 y 轴，一般情况下单个 grid 组件最多只能放左右两个 y 轴，多于两个 y 轴需要通过配置 offset 属性防止同个位置多个 Y 轴的重叠
     */
    private Object yAxis;
    /**
     * 三维笛卡尔坐标系组件。需要和 xAxis3D，yAxis3D，zAxis3D 三个坐标轴组件一起使用。
     * 可以在三维笛卡尔坐标系上绘制三维折线图，三维柱状图，三维散点/气泡图，曲面图。
     */
    private Object grid3D;
    /**
     * 三维笛卡尔坐标系中的 x 轴。可以通过 grid3DIndex 索引所在的三维笛卡尔坐标系。
     */
    private Object xAxis3D;
    /**
     * 三维笛卡尔坐标系中的 y 轴。可以通过 grid3DIndex 索引所在的三维笛卡尔坐标系。
     */
    private Object yAxis3D;
    /**
     * 三维笛卡尔坐标系中的 z 轴。可以通过 grid3DIndex 索引所在的三维笛卡尔坐标系。
     */
    private Object zAxis3D;
    /**
     * 极坐标系，可以用于散点图和折线图。每个极坐标系拥有一个角度轴和一个半径轴
     */
    private Polar polar;
    /**
     * 极坐标系的径向轴
     */
    private RadiusAxis radiusAxis;
    /**
     * 极坐标系的角度轴
     */
    private AngleAxis angleAxis;
    /**
     * 雷达图坐标系组件
     */
    private Object radar;
    /**
     * 数据区域缩放（详见dataZoom）,数据展现范围选择
     */
    private Object dataZoom;
    /**
     * visualMap 是视觉映射组件，用于进行『视觉编码』，也就是将数据映射到视觉元素（视觉通道）
     */
    private Object visualMap;
    /**
     * 提示框组件
     */
    private Tooltip tooltip;
    /**
     * 工具箱（详见toolbox），每个图表最多仅有一个工具箱
     */
    private Toolbox toolbox;
    /**
     * brush 是区域选择组件，用户可以选择图中一部分数据，从而便于向用户展示被选中数据，或者他们的一些统计计算结果
     */
    private Brush brush;
    /**
     * 地理坐标系组件
     */
    private Object geo;
    /**
     * 百度地图
     */
    private Bmap bmap;
    /**
     * 平行坐标系介绍
     */
    private Parallel parallel;
    /**
     * 平行坐标系中的坐标轴。
     */
    private Object parallelAxis;
    /**
     * 单轴。可以被应用到散点图中展现一维数据
     */
    private Object singleAxis;
    /**
     * timeline 组件，提供了在多个 ECharts option 间进行切换、播放等操作的功能
     */
    private Timeline timeline;
    /**
     * graphic 是原生图形元素组件
     */
    private List<Graphic> graphic;
    /**
     * 系列列表。每个系列通过 type 决定自己的图表类型
     */
    private Object series;
    /**
     * 日历坐标系组件,@since 3.5.1
     */
    private Object calendar;
    /**
     * 坐标轴指示器是指示坐标轴当前刻度的工具,这是坐标轴指示器（axisPointer）的全局公用设置。
     *
     * @since 3.5.1
     */
    private AxisPointer axisPointer;
    /**
     * ECharts 4 开始支持了 数据集（dataset）组件用于单独的数据集声明，从而数据可以单独管理，被多个组件复用，并且可以自由指定数据到视觉的映射。这在不少场景下能带来使用上的方
     */
    private Dataset dataset;

    private Option baseOption;

    private List<Option> options;

    public Option getBaseOption() {
        return baseOption;
    }

    public void setBaseOption(Option baseOption) {
        this.baseOption = baseOption;
    }

    public List<Option> getOptions() {
        return options;
    }

    public void setOptions(List<Option> options) {
        this.options = options;
    }

    public Dataset dataset() {
        if (dataset == null)
            dataset = new Dataset();
        return dataset;
    }

    public Option dataset(Dataset dataset) {
        this.dataset = dataset;
        return this;
    }

    public AxisPointer axisPointer() {
        if (axisPointer == null)
            axisPointer = new AxisPointer();
        return axisPointer;
    }

    public Option axisPointer(AxisPointer axisPointer) {
        this.axisPointer = axisPointer;
        return this;
    }

    public Option calendar(Object... values) {
        if (values.length == 1)
            this.calendar = values[0];
        else
            this.calendar = values;
        return this;
    }

    public Option title(Title title) {
        this.title = title;
        return this;
    }

    public Legend legend() {
        if (this.legend == null)
            this.legend = new Legend();
        return this.legend;
    }

    public Option legend(Legend legend) {
        this.legend = legend;
        return this;
    }

    public Option grid(Grid... values) {
        if (values.length == 1)
            this.grid = values[0];
        else
            this.grid = values;
        return this;
    }

    public Option xAxis(Axis... values) {
        if (values.length == 1)
            this.xAxis = values[0];
        else
            this.xAxis = values;
        return this;
    }

    public Option yAxis(Axis... values) {
        if (values.length == 1)
            this.yAxis = values[0];
        else
            this.yAxis = values;
        return this;
    }

    public Grid3D grid3D() {
        if (this.grid3D == null) {
            this.grid3D = new Grid3D();
        }
        return (Grid3D) this.grid3D;
    }

    public Option grid3D(Grid3D... values) {
        if (values.length == 1)
            this.grid3D = values[0];
        else
            this.grid3D = values;
        return this;
    }

    public Axis3D xAxis3D() {
        if (this.xAxis3D == null) {
            this.xAxis3D = new Axis3D();
        }
        return (Axis3D) this.xAxis3D;
    }

    public Option xAxis3D(Axis3D... values) {
        if (values.length == 1)
            this.xAxis3D = values[0];
        else
            this.xAxis3D = values;
        return this;
    }

    public Axis3D yAxis3D() {
        if (this.yAxis3D == null) {
            this.yAxis3D = new Axis3D();
        }
        return (Axis3D) this.yAxis3D;
    }

    public Option yAxis3D(Axis3D... values) {
        if (values.length == 1)
            this.yAxis3D = values[0];
        else
            this.yAxis3D = values;
        return this;
    }

    public Axis3D zAxis3D() {
        if (this.zAxis3D == null) {
            this.zAxis3D = new Axis3D();
        }
        return (Axis3D) this.zAxis3D;
    }

    public Option zAxis3D(Axis3D... values) {
        if (values.length == 1)
            this.zAxis3D = values[0];
        else
            this.zAxis3D = values;
        return this;
    }

    public Polar polar() {
        if (this.polar == null)
            this.polar = new Polar();
        return this.polar;
    }

    public Option polar(Polar polar) {
        this.polar = polar;
        return this;
    }

    public RadiusAxis radiusAxis() {
        if (this.radiusAxis == null)
            this.radiusAxis = new RadiusAxis();
        return this.radiusAxis;
    }

    public Option radiusAxis(RadiusAxis radiusAxis) {
        this.radiusAxis = radiusAxis;
        return this;
    }

    public AngleAxis angleAxis() {
        if (this.angleAxis == null)
            this.angleAxis = new AngleAxis();
        return this.angleAxis;
    }

    public Option angleAxis(AngleAxis angleAxis) {
        this.angleAxis = angleAxis;
        return this;
    }

    public Object radar() {
        if (this.radar == null)
            this.radar = new Radar();
        return this.radar;
    }

    public Option radar(Radar radar) {
        this.radar = radar;
        return this;
    }

    public Option dataZoom(DataZoom... values) {
        if (values.length == 1)
            this.dataZoom = values[0];
        else
            this.dataZoom = values;
        return this;
    }

    public Option visualMap(Object... values) {
        if (values.length == 1)
            this.visualMap = values[0];
        else
            this.visualMap = values;
        return this;
    }

    public Tooltip tooltip() {
        if (this.tooltip == null)
            this.tooltip = new Tooltip();
        return this.tooltip;
    }

    public Option tooltip(Tooltip tooltip) {
        this.tooltip = tooltip;
        return this;
    }

    public Toolbox toolbox() {
        if (this.toolbox == null)
            this.toolbox = new Toolbox();
        return this.toolbox;
    }

    public Option toolbox(Toolbox toolbox) {
        this.toolbox = toolbox;
        return this;
    }

    public Brush brush() {
        if (this.brush == null)
            this.brush = new Brush();
        return this.brush;
    }

    public Option brush(Brush brush) {
        this.brush = brush;
        return this;
    }

    public Option geo(Brush brush) {
        this.brush = brush;
        return this;
    }

    public Bmap bmap() {
        if (this.bmap == null)
            this.bmap = new Bmap();
        return this.bmap;
    }

    public Option bmap(Bmap bmap) {
        this.bmap = bmap;
        return this;
    }

    public Parallel parallel() {
        if (this.parallel == null)
            this.parallel = new Parallel();
        return this.parallel;
    }

    public Option parallel(Parallel parallel) {
        this.parallel = parallel;
        return this;
    }

    public Option parallelAxis(Object... values) {
        if (values.length == 1)
            this.parallelAxis = values[0];
        else
            this.parallelAxis = values;
        return this;
    }

    public Option singleAxis(Object... values) {
        if (values.length == 1)
            this.singleAxis = values[0];
        else
            this.singleAxis = values;
        return this;
    }

    public Timeline timeline() {
        if (this.timeline == null)
            this.timeline = new Timeline();
        return this.timeline;
    }

    public Option timeline(Timeline timeline) {
        this.timeline = timeline;
        return this;
    }

    public Graphic graphic(String type) {
        if (this.graphic == null)
            this.graphic = new ArrayList<Graphic>();
        Graphic grap = null;
        if (type.equalsIgnoreCase("arc"))
            grap = new Arc();
        else if (type.equalsIgnoreCase("bezierCurve"))
            grap = new BezierCurve();
        else if (type.equalsIgnoreCase("circle"))
            grap = new Circle();
        else if (type.equalsIgnoreCase("group"))
            grap = new Group();
        else if (type.equalsIgnoreCase("image"))
            grap = new Image();
        else if (type.equalsIgnoreCase("line"))
            grap = new Line();
        else if (type.equalsIgnoreCase("polygon"))
            grap = new Polygon();
        else if (type.equalsIgnoreCase("polyline"))
            grap = new Polyline();
        else if (type.equalsIgnoreCase("rect"))
            grap = new Rect();
        else if (type.equalsIgnoreCase("ring"))
            grap = new Ring();
        else if (type.equalsIgnoreCase("sector"))
            grap = new Sector();
        else if (type.equalsIgnoreCase("text"))
            grap = new Text();
        this.graphic.add(grap);
        return grap;
    }

    public Option graphic(Graphic... values) {
        if (values == null || values.length == 0) {
            return this;
        }
        if (this.graphic == null)
            this.graphic = new ArrayList<Graphic>();
        this.graphic.addAll(Arrays.asList(values));
        return this;
    }

    public Object series(Object... values) {
        if (values.length == 1)
            this.series = values[0];
        return this;
    }

    public Object backgroundColor() {
        return backgroundColor;
    }

    public Option backgroundColor(Object backgroundColor) {
        this.backgroundColor = backgroundColor;
        return this;
    }

    public Object[] color() {
        return color;
    }

    public Option color(Object... color) {
        this.color = color;
        return this;
    }

    public TextStyle textStyle() {
        return textStyle;
    }

    public Option textStyle(TextStyle textStyle) {
        this.textStyle = textStyle;
        return this;
    }


    public Object blendMode() {
        return blendMode;
    }

    public Option blendMode(String blendMode) {
        this.blendMode = blendMode;
        return this;
    }

    public Object hoverLayerThreshold() {
        return hoverLayerThreshold;
    }

    public Option hoverLayerThreshold(Integer hoverLayerThreshold) {
        this.hoverLayerThreshold = hoverLayerThreshold;
        return this;
    }

    public Object getBackgroundColor() {
        return backgroundColor;
    }

    public void setBackgroundColor(Object backgroundColor) {
        this.backgroundColor = backgroundColor;
    }

    public Object[] getColor() {
        return color;
    }

    public void setColor(Object[] color) {
        this.color = color;
    }

    public TextStyle getTextStyle() {
        return textStyle;
    }

    public void setTextStyle(TextStyle textStyle) {
        this.textStyle = textStyle;
    }

    public String getBlendMode() {
        return blendMode;
    }

    public void setBlendMode(String blendMode) {
        this.blendMode = blendMode;
    }

    public Integer getHoverLayerThreshold() {
        return hoverLayerThreshold;
    }

    public void setHoverLayerThreshold(Integer hoverLayerThreshold) {
        this.hoverLayerThreshold = hoverLayerThreshold;
    }

    public Object getTitle() {
        return title;
    }

    public void setTitle(Title title) {
        this.title = title;
    }

    public Legend getLegend() {
        return legend;
    }

    public void setLegend(Legend legend) {
        this.legend = legend;
    }

    public Object getGrid() {
        return grid;
    }

    public void setGrid(List<Grid> grid) {
        this.grid = grid;
    }

    public Object getxAxis() {
        return xAxis;
    }

    public void setxAxis(Object xAxis) {
        this.xAxis = xAxis;
    }

    public Object getyAxis() {
        return yAxis;
    }

    public void setyAxis(Object yAxis) {
        this.yAxis = yAxis;
    }

    public Object getGrid3D() {
        return grid3D;
    }

    public void setGrid3D(List<Grid3D> grid3D) {
        this.grid3D = grid3D;
    }

    public Object getxAxis3D() {
        return xAxis3D;
    }

    public void setxAxis3D(Object xAxis3D) {
        this.xAxis3D = xAxis3D;
    }

    public Object getyAxis3D() {
        return yAxis3D;
    }

    public void setyAxis3D(Object yAxis3D) {
        this.yAxis3D = yAxis3D;
    }

    public Object getzAxis3D() {
        return zAxis3D;
    }

    public void setzAxis3D(Object zAxis3D) {
        this.zAxis3D = zAxis3D;
    }

    public Polar getPolar() {
        return polar;
    }

    public void setPolar(Polar polar) {
        this.polar = polar;
    }

    public RadiusAxis getRadiusAxis() {
        return radiusAxis;
    }

    public void setRadiusAxis(RadiusAxis radiusAxis) {
        this.radiusAxis = radiusAxis;
    }

    public AngleAxis getAngleAxis() {
        return angleAxis;
    }

    public void setAngleAxis(AngleAxis angleAxis) {
        this.angleAxis = angleAxis;
    }

    public Object getRadar() {
        return radar;
    }

    public void setRadar(Object radar) {
        this.radar = radar;
    }

    public Object getDataZoom() {
        return dataZoom;
    }

    public void setDataZoom(Object dataZoom) {
        this.dataZoom = dataZoom;
    }

    public Object getVisualMap() {
        return visualMap;
    }

    public void setVisualMap(List<VisualMap> visualMap) {
        this.visualMap = visualMap;
    }

    public Tooltip getTooltip() {
        return tooltip;
    }

    public void setTooltip(Tooltip tooltip) {
        this.tooltip = tooltip;
    }

    public Toolbox getToolbox() {
        return toolbox;
    }

    public void setToolbox(Toolbox toolbox) {
        this.toolbox = toolbox;
    }

    public Brush getBrush() {
        return brush;
    }

    public void setBrush(Brush brush) {
        this.brush = brush;
    }

    public Object getGeo() {
        return geo;
    }

    public void setGeo(Object geo) {
        this.geo = geo;
    }

    public Parallel getParallel() {
        return parallel;
    }

    public void setParallel(Parallel parallel) {
        this.parallel = parallel;
    }

    public Object getParallelAxis() {
        return parallelAxis;
    }

    public void setParallelAxis(Object parallelAxis) {
        this.parallelAxis = parallelAxis;
    }

    public Object getSingleAxis() {
        return singleAxis;
    }

    public void setSingleAxis(List<BaseAxis> singleAxis) {
        this.singleAxis = singleAxis;
    }

    public Timeline getTimeline() {
        return timeline;
    }

    public void setTimeline(Timeline timeline) {
        this.timeline = timeline;
    }

    public List<Graphic> getGraphic() {
        return graphic;
    }

    public void setGraphic(List<Graphic> graphic) {
        this.graphic = graphic;
    }

    public Bmap getBmap() {
        return bmap;
    }

    public void setBmap(Bmap bmap) {
        this.bmap = bmap;
    }

    public Object getCalendar() {
        return calendar;
    }

    public void setCalendar(Object calendar) {
        this.calendar = calendar;
    }

    public AxisPointer getAxisPointer() {
        return axisPointer;
    }

    public void setAxisPointer(AxisPointer axisPointer) {
        this.axisPointer = axisPointer;
    }

    public Object getSeries() {
        return series;
    }

    public void setSeries(Object series) {
        this.series = series;
    }

    public Dataset getDataset() {
        return dataset;
    }

    public void setDataset(Dataset dataset) {
        this.dataset = dataset;
    }
}
